home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 2000 July / macformat-092.iso / Dreamweaver 3 / Configuration / Commands / Clean Up Word HTML.js < prev    next >
Encoding:
Text File  |  1999-12-01  |  50.4 KB  |  2,016 lines

  1. //
  2. // Copyright 1999 Macromedia, Inc. All rights reserved. 
  3. // --------------------------------------------------------------------------
  4. //
  5. // Import Word HTML.js
  6. //
  7. // This command is similar to the "Clean Up HTML.js" command, except that it
  8. // is specifically designed to work with HTML documents generated by
  9. // Microsoft Word.
  10. //
  11. // --------------------------------------------------------------------------
  12.  
  13.  
  14. //******************* Commands API *******************
  15.     
  16. function commandButtons()
  17. {
  18.    return new Array( BTN_OK,     "importWordHTML()",  // main entry point
  19.                      BTN_Cancel, "window.close()",
  20.                      BTN_Help,   "displayHelp()");
  21. }
  22.  
  23. function canAcceptCommand()
  24. {
  25.   return (dw.getFocus() == 'document');
  26. }
  27.  
  28.    
  29. //******************* Global Variables *******************
  30.  
  31. var helpDoc = MM.HELP_cmdCleanUpWordHTML;
  32.  
  33. var gWordVersion;
  34. var CB;               // The checkbox group
  35. var CBTags;           // The Checkboxes in the dialog
  36.  
  37. // Logging vars
  38. var gRemoveMetaTags = 0;
  39. var gRemoveWordXML = 0;
  40. var gRemoveConditionals = 0;
  41. var gRemoveEmptyParas = 0;
  42. var gRemoveMargins = 0;
  43. var gRemoveInlineCSS = 0;
  44. var gRemovemsoStyle = 0;
  45. var gRemoveNonCSS = 0;
  46. var gRemoveTableCSS = 0;
  47. var gRemoveUnusedCSS = 0;
  48.  
  49. var gFontsConverted = 0;
  50.  
  51. var gNestingFixed = 0;
  52. var gBackgroundSet = "";
  53. var gSourceFormatted = 0;
  54.  
  55.  
  56. //************** Main functions *********************
  57.  
  58. /////////////////////////////////////////////////////////////////////////////
  59. // Function
  60. //    importWordHTML
  61. //
  62. // Purpose
  63. //    This is the "main" function that the dialog calls when the user
  64. //    clicks OK.
  65. //
  66. function importWordHTML()
  67. {
  68.    T.finish(); //ensure Tabs are through getting input
  69.  
  70.    // Lets save the settings first.  That way if something crashes or
  71.    // goes wrong during the processing, the user doesn't need to reset
  72.    // all of the options again.
  73.    if(doSaveSettings())
  74.       saveSettings();
  75.  
  76.    // Set up logging particulars
  77.    if ( doShowLog() )
  78.    {  
  79.       MM_enableLogging();
  80.       MM_clearLog();
  81.    }
  82.    else
  83.    {
  84.       MM_disableLogging();
  85.    }
  86.  
  87.    version = getVersion();
  88.  
  89.    switch(version)
  90.    {
  91.       case "2000":
  92.          ProcessWord2000();
  93.          break;
  94.  
  95.       case "97":
  96.          ProcessWord97();
  97.          break;
  98.    }
  99.  
  100.    MM.setBusyCursor();
  101.     
  102.    // Do some processing that needs to be done no matter the version.
  103.    GeneralProcessing();
  104.  
  105.    // Cleanup
  106.    PostProcess();
  107.    
  108.    MM.clearBusyCursor();
  109.     
  110.    // Show the log, if they said to.
  111.    finish();
  112. }
  113.  
  114.  
  115. /////////////////////////////////////////////////////////////////////////////
  116. function GeneralProcessing()
  117. {
  118.    if(doRemoveMetaLink())
  119.       removeMetaLink();
  120.  
  121.    if(doSetBgColor())
  122.       setBgColor();
  123. }
  124.  
  125.  
  126. /////////////////////////////////////////////////////////////////////////////
  127. // Function
  128. //    PostProcess
  129. //
  130. // Purpose
  131. //    Anything that needs to be done after we have done all of the cleaning
  132. //    should be done in here.  This gets run no matter what options are
  133. //    turned on.
  134. //
  135. function PostProcess()
  136. {
  137.    var root = dw.getDocumentDOM('document').documentElement;
  138.    var html;
  139.    
  140.    // Remove the blank style="" attributes.
  141.    html = root.outerHTML;
  142.    html = html.replace(/\s*style=(""|'')/g, "");
  143.    root.outerHTML = html;
  144.  
  145.    RemoveEmptyTags();
  146.  
  147.    if(doApplySourceFormatting())
  148.    {
  149.       // Included from "Source Formatting.js".
  150.       formatSource();
  151.       
  152.       gSourceFormatted = 1;
  153.    }
  154. }
  155.  
  156.  
  157. /////////////////////////////////////////////////////////////////////////////
  158. // Function
  159. //    initialize
  160. //
  161. // Purpose
  162. //    This is called from body onLoad to initialize the dialog.
  163. //
  164. function initialize()
  165. {
  166.    getCheckboxNames();
  167.    
  168.    // Initialize the checkboxes.
  169.    initCheckboxes();
  170.    
  171.    // Ok, we have hooked up all of the checkboxes.  Now we need to set
  172.    // them to initial values of some kind.
  173.    setCheckboxStates();
  174.  
  175.    //Initialize the TabControl.  (Pass in the prefix used for the tab layers)
  176.    T = new TabControl('Tab');
  177.     
  178.    //Add tab pages.   (Pass the layer name, and the page object)
  179.    T.addPage('basic', new Pg1(LABEL_Basic));
  180.    T.addPage('detailWord2000', new Pg2(LABEL_Detailed));
  181.    T.addPage('detailWord97', new Pg3(LABEL_Detailed));
  182.  
  183.    T.addGroup("group2000", new Array("basic","detailWord2000"));
  184.    T.addGroup("group97", new Array("basic","detailWord97"));
  185.  
  186.    //Show default group
  187.    T.showGroup("group97");
  188.  
  189.    //Initialize and display the tabs.  (Could pass the name of a page to start on)
  190.    T.start();
  191.  
  192.    // Determine what version of Word this thing came from.
  193.    detectWordVersion();
  194.  
  195.    setWordVersion();
  196. }
  197.  
  198.  
  199. /////////////////////////////////////////////////////////////////////////////
  200. // Function
  201. //    setDropDownStates
  202. //
  203. // Purpose
  204. //    Retrieve the settings for the font drop downs from the MetaFile.
  205. //
  206. function setDropDownStates()
  207. {
  208.    var path = document.URL;
  209.    var name, font, value, valueStr;
  210.    var metaFile;
  211.  
  212.    metaFile = MMNotes.open(path, false);
  213.  
  214.    if(metaFile != 0)
  215.    {
  216.       // We have some stored settings.  Set the checkboxes based on them.
  217.       for(i = 1; i <= 7; i++)
  218.       {
  219.          name = "menuSize" + i;
  220.          font = findObject(name);
  221.          valueStr = MMNotes.get(metaFile, name);
  222.          
  223.          if (font != null && valueStr) {
  224.            value = parseInt(valueStr);
  225.  
  226.            if((valueStr == value.toString) && (value >= 0) && (value < fontValues.length))
  227.               font.selectedIndex = value;
  228.          }
  229.       }
  230.  
  231.       // We are done with the file, close it.
  232.       MMNotes.close(metaFile);
  233.       metaFile = 0;
  234.    }
  235.    
  236.    // Note that the dropdowns are initialized to some default settings
  237.    // in initDropDowns().  So if there are no keys in the metafile,
  238.    // the dropdowns will be set to something appropriate.
  239. }
  240.  
  241.  
  242. /////////////////////////////////////////////////////////////////////////////
  243. // Function
  244. //    initDropDowns
  245. //
  246. // Purpose
  247. //    Initialize the convert font sizes drop downs with the array that
  248. //    is defined in the .htm file.
  249. //
  250. function initDropDowns()
  251. {
  252.    var i, j;
  253.    var font;
  254.    var select;
  255.  
  256.    for(i = 1; i <= 7; i++)
  257.    {
  258.       font = findObject("menuSize"+i);
  259.  
  260.       // Select something appropriate as a default.
  261.       switch(i)
  262.       {
  263.          case 1:
  264.             select = 6;
  265.             break;
  266.  
  267.          case 2:
  268.             select = 7;
  269.             break;
  270.             
  271.          case 3:
  272.             select = 1;
  273.             break;
  274.             
  275.          case 4:
  276.          case 5:
  277.          case 6:
  278.          case 7:
  279.             select = 0;
  280.             break;
  281.       }
  282.       
  283.       if(font != null)
  284.         loadSelectList(font, fontValues, true, select);
  285.    }
  286. }
  287.  
  288.  
  289. /////////////////////////////////////////////////////////////////////////////
  290. // Function
  291. //    getCheckboxNames
  292. //
  293. // Purpose
  294. //    Search through our dialog and find all of our "checkboxes" and store
  295. //    their names.  This way, if we add or delete them, we don't have to
  296. //    do as much maintainence.
  297. //
  298. function getCheckboxNames()
  299. {
  300.    CBTags = new Array();
  301.    traverse(document.documentElement, getCheckboxes);
  302. }
  303.  
  304.  
  305. /////////////////////////////////////////////////////////////////////////////
  306. // Function
  307. //    getCheckboxes
  308. //
  309. // Purpose
  310. //    This finds each "checkbox" input in our dialog and adds the tag
  311. //    to our list.  This way we can easily search the checkboxes.
  312. //    
  313. function getCheckboxes(tag)
  314. {
  315.    var tagName = tag.tagName.toUpperCase();
  316.  
  317.    if(tagName != "INPUT")
  318.       return true;
  319.  
  320.    click = tag.getAttribute("onClick");
  321.  
  322.    if(click != null && click.match(/CB\.clicked/))
  323.    {
  324.       // This is a checkbox add its name to the list.
  325.       CBTags.push(tag);
  326.    }
  327.  
  328.    return true;
  329. }
  330.  
  331.  
  332. /////////////////////////////////////////////////////////////////////////////
  333. // Function
  334. //    initCheckboxes
  335. //
  336. // Purpose
  337. //    Create and hookup the hierarchical checkboxes.  Note, the hierarchy is
  338. //    stored in the "parents" attribute on the checkbox in the HTML.  This
  339. //    way, the HTML file sepecifies the relationship and the javascript
  340. //    doesn't care.  Saves us maintainence time when changing the checkboxes.
  341. //
  342. function initCheckboxes()
  343. {
  344.    CB = new CheckboxSet();
  345.  
  346.    // Add the "parent" checkboxes first because they need to exist
  347.    // for the child checkboxes to name them as a parent.  Parent
  348.    // checkboxes have no "parents" attribute.
  349.    for(i = 0; i < CBTags.length; i++)
  350.    {
  351.       parents = CBTags[i].getAttribute("parents");
  352.  
  353.       if(parents == null || parents == "")
  354.          CB.addCheckbox(CBTags[i].getAttribute("name"));
  355.    }
  356.  
  357.    // Now that all of the parent checkboxes have been registered,
  358.    // we can now register the child checkboxes.
  359.    for(i = 0; i < CBTags.length; i++)
  360.    {
  361.       parents = CBTags[i].getAttribute("parents");
  362.  
  363.       if(parents != null && parents != "")
  364.       {
  365.          CB.addCheckbox(CBTags[i].getAttribute("name"),
  366.             CBTags[i].getAttribute("parents"));
  367.       }
  368.    }
  369.  
  370. }
  371.  
  372.  
  373. /////////////////////////////////////////////////////////////////////////////
  374. // Function
  375. //    setCheckboxStates
  376. //
  377. // Purpose
  378. //    Set the checkbox states based on the saved defaults, or if we don't
  379. //    have any saved defaults, set the checkboxes to our hard coded
  380. //    defaults.
  381. //
  382. function setCheckboxStates()
  383. {
  384.    if(setCheckboxStatesFromSavedDefaults())
  385.       return;
  386.    
  387.    // Default settings.  Turn all options on by default.
  388.    for(i = 0; i < CBTags.length; i++)
  389.       CB.check(CBTags[i].getAttribute("name"), true);
  390.  
  391. }
  392.  
  393.  
  394. /////////////////////////////////////////////////////////////////////////////
  395. // Function
  396. //    setCheckboxStatesFromSavedDefaults
  397. //
  398. // Purpose
  399. //    Set the checkboxes based on the defaults that we have saved.
  400. //
  401. // Returns
  402. //    true if we were able to read info from the metafile. false if we
  403. //    could not read the metafile (didn't exist, etc) and we should set
  404. //    some defaults ourselves.
  405. //
  406. function setCheckboxStatesFromSavedDefaults()
  407. {
  408.    var path = document.URL;
  409.    var metaFile = MMNotes.open(path, false);
  410.  
  411.    if(metaFile != 0)
  412.    {
  413.       // We have some stored settings.  Set the checkboxes based on them.
  414.       var keys = MMNotes.getKeys(metaFile);
  415.       var i, j;
  416.  
  417.       for(i = 0; i < keys.length; i++)
  418.       {
  419.          for(j = 0; j < CBTags.length; j++)
  420.          {
  421.             if(keys[i] == CBTags[j].getAttribute("name"))
  422.             {
  423.                CB.check(CBTags[j].getAttribute("name"), true);
  424.                break;
  425.             }
  426.          }
  427.       }
  428.  
  429.  
  430.       // We are done with the file, close it.
  431.       MMNotes.close(metaFile);
  432.       metaFile = 0;
  433.  
  434.       return true;
  435.    }
  436.    else
  437.    {
  438.       // No settings to read.
  439.       return false;
  440.    }
  441.    
  442.    return false;
  443. }
  444.  
  445.  
  446. /////////////////////////////////////////////////////////////////////////////
  447. // Function
  448. //    finish
  449. //
  450. // Purpose
  451. //    We are done.  Do any last minute stuff and show any log information
  452. //    that user may have requested.
  453. //
  454. function finish()
  455. {
  456.    // Show what we did if show log is enabled
  457.    if ( doShowLog() )
  458.    {
  459.       var bDidSomething = (        
  460.                         (gRemoveMetaTags > 0)      ||
  461.                         (gRemoveWordXML > 0)       ||
  462.                         (gRemoveConditionals > 0)  ||
  463.                         (gRemoveEmptyParas > 0)    ||
  464.                         (gRemoveMargins > 0)       ||
  465.                         (gRemoveInlineCSS > 0)     ||
  466.                         (gRemovemsoStyle > 0)      ||
  467.                         (gRemoveNonCSS > 0)        ||
  468.                         (gRemoveTableCSS > 0)      ||
  469.                         (gRemoveUnusedCSS > 0)     ||
  470.                         (gFontsConverted > 0)      ||
  471.                         (gNestingFixed > 0)        ||
  472.                         (gBackgroundSet != "")     ||
  473.                         (gSourceFormatted > 0)       );
  474.       
  475.       MM_note(MSG_TrcSummaryHeader);
  476.  
  477.       if(bDidSomething)
  478.       {                             
  479.          if(gRemoveMetaTags > 0) 
  480.             MM_note(MSG_TrcRemoveMetaTags, gRemoveMetaTags);
  481.  
  482.          if(gRemoveWordXML > 0)
  483.             MM_note(MSG_TrcRemoveWordXML, gRemoveWordXML);
  484.  
  485.          if(gRemoveConditionals > 0)
  486.             MM_note(MSG_TrcRemoveConditionals, gRemoveConditionals);
  487.  
  488.          if(gRemoveEmptyParas > 0)
  489.             MM_note(MSG_TrcRemoveEmptyParas, gRemoveEmptyParas);
  490.  
  491.          if(gRemoveMargins > 0)
  492.             MM_note(MSG_TrcRemoveMargins, gRemoveMargins);
  493.  
  494.          if(gRemoveInlineCSS > 0)
  495.             MM_note(MSG_TrcRemoveInlineCSS, gRemoveInlineCSS);
  496.  
  497.          if(gRemovemsoStyle > 0)
  498.             MM_note(MSG_TrcRemovemsoStyle, gRemovemsoStyle);
  499.  
  500.          if(gRemoveNonCSS > 0)
  501.             MM_note(MSG_TrcRemoveNonCSS, gRemoveNonCSS);
  502.  
  503.          if(gRemoveTableCSS > 0)
  504.             MM_note(MSG_TrcRemoveTableCSS, gRemoveTableCSS);
  505.  
  506.          if(gRemoveUnusedCSS > 0)
  507.             MM_note(MSG_TrcRemoveUnusedCSS, gRemoveUnusedCSS);
  508.  
  509.          if(gFontsConverted > 0)
  510.             MM_note(MSG_TrcFontsConverted, gFontsConverted);
  511.  
  512.          if(gNestingFixed > 0)
  513.             MM_note(MSG_TrcNestingFixed, gNestingFixed);
  514.  
  515.          if(gBackgroundSet != "")
  516.             MM_note(MSG_TrcBackgroundSet, gBackgroundSet);
  517.  
  518.          if(gSourceFormatted > 0)
  519.             MM_note(MSG_TrcSourceFormatted);
  520.       }
  521.       else
  522.       {
  523.          MM_note( MSG_TrcDidNothing );
  524.       }
  525.                      
  526.       MM_showLog();
  527.    }
  528.  
  529.    window.close();         
  530. }
  531.  
  532.  
  533. /////////////////////////////////////////////////////////////////////////////
  534. // Function
  535. //    saveSettings
  536. //
  537. // Purpose
  538. //    Save the options that the user has selected so that the next time
  539. //    they use this dialog, it will have their last settings.
  540. //
  541. function saveSettings()
  542. {
  543.    var path = document.URL;
  544.    var metaFile = MMNotes.open(path, true);
  545.    var name;
  546.  
  547.    if(metaFile == 0)
  548.    {
  549.       alert(wrapTextForAlert(MSG_metaFileError, 80));
  550.       return;
  551.    }
  552.    
  553.    // Make sure the meta file does not contain stale information.
  554.    clearMetaFile(metaFile);
  555.    
  556.    // Now set a key for each option that is on.
  557.    for(i = 0; i < CBTags.length; i++)
  558.    {
  559.       name = CBTags[i].getAttribute("name");
  560.       if(CB.isChecked(name))
  561.          MMNotes.set(metaFile, name, "1");
  562.    }
  563.  
  564.    // Now, save the state of the "convert fonts" things.
  565.    for(i = 1; i <= 7; i++)
  566.    {
  567.       name = "menuSize" + i;
  568.       font = findObject(name);
  569.  
  570.       if(font != null)
  571.          MMNotes.set(metaFile, name, font.selectedIndex+"");
  572.    }
  573.  
  574.    MMNotes.close(metaFile);
  575.    metaFile = 0;
  576. }
  577.  
  578.  
  579. /////////////////////////////////////////////////////////////////////////////
  580. // Function
  581. //    clearMetaFile
  582. //
  583. // Purpose
  584. //    Clear the metafile so that we don't have stale info in there.
  585. //
  586. function clearMetaFile(metaFile)
  587. {
  588.    if(metaFile == 0)
  589.       return;
  590.       
  591.    var keys = MMNotes.getKeys(metaFile);
  592.  
  593.    for(i = 0; i < keys.length; i++)
  594.       MMNotes.remove(metaFile, keys[i]);
  595. }
  596.  
  597. // ----------- Autodetection routines ----------------
  598.  
  599. /////////////////////////////////////////////////////////////////////////////
  600. // Function
  601. //    detectWordVersion
  602. //
  603. // Purpose
  604. //    Find out what version of Word the document was generated by.  We do
  605. //    this so that the user doesn't need to worry about it.
  606. //
  607. function detectWordVersion()
  608. {
  609.    var bFoundVersion = true;
  610.    
  611.    // Init gWordVersion
  612.    gWordVersion = -1;
  613.    
  614.    // This will set 'gWordVersion' if it finds anything
  615.    traverse(null, findVersionInMetaTag);
  616.    
  617.    if(gWordVersion == -1)
  618.    {
  619.       // We could not determine the version of Word used to generate this
  620.       // document.  Default to Word 2000.
  621.       gWordVersion = 2000;
  622.       bFoundVersion = false;
  623.    }
  624.  
  625.    // Set the dropdown to have what we have detected.
  626.  
  627.    with(findObject("selectWordVersion"))
  628.    {
  629.       for(i = 0; i < options.length; i++)
  630.       {
  631.          if(options[i].value == gWordVersion)
  632.          {
  633.             selectedIndex = i;
  634.             break;
  635.          }
  636.       }
  637.    }
  638.  
  639.    if(!bFoundVersion)
  640.    {
  641.       // Notify the user that we were unable to determine the version of Word.
  642.       alert(wrapTextForAlert(MSG_UnknownVersion, 80));
  643.    }
  644.    return gWordVersion;
  645. }
  646.  
  647.  
  648. /////////////////////////////////////////////////////////////////////////////
  649. // Function
  650. //    findVersionInMetaTag
  651. //
  652. // Purpose
  653. //    This is a callback from traverse.  This function is the meat of
  654. //    finding the version of Word used to generate the HTML.  We look
  655. //    at the meta tags and find the one that gives the version of Word.
  656. //
  657. function findVersionInMetaTag(tag)
  658. {
  659.    tagName = tag.tagName;
  660.    if(tagName.toUpperCase() == "META")
  661.    {
  662.       name = tag.getAttribute("NAME");
  663.       if(name != null && name.toUpperCase() == "GENERATOR")
  664.       {
  665.          content = tag.getAttribute("CONTENT");
  666.          if(content != null)
  667.          {
  668.             if(content.search(/word 97/i) >= 0)
  669.             {
  670.                gWordVersion = 97;
  671.                return false;
  672.             }
  673.             else if(content.search(/word 81/i) >= 0)
  674.             {
  675.                gWordVersion = 97;
  676.                return false;
  677.             }
  678.             else if(content.search(/word 9/i) >= 0)
  679.             {
  680.                gWordVersion = 2000;
  681.                return false;
  682.             }
  683.          }
  684.       }
  685.    }
  686.  
  687.    return true;
  688. }
  689.  
  690.  
  691. /////////////////////////////////////////////////////////////////////////////
  692. // Function
  693. //    setWordVersion
  694. //
  695. // Purpose
  696. //    This gets called when the user selects a different version of Word
  697. //    from the drop down list.  This grabs the selected value from the
  698. //    drop down and shows the appropriate options by hiding or showing
  699. //    the different layers.
  700. //
  701. function setWordVersion()
  702. {
  703.    version = getVersion();
  704.    
  705.    if(version != gWordVersion)
  706.    {
  707.       // The user is trying to select the options for a version of
  708.       // word that does not match what we think it is.  Allow them
  709.       // to to do this, but warn them that in doing so the import
  710.       // may not work since the algorithms for the different versions
  711.       // are different.
  712.  
  713.       alert(wrapTextForAlert(MSG_DiffWordVersion, 80));
  714.    }
  715.    
  716.    switch(version)
  717.    {
  718.       case "2000":
  719.          T.showGroup("group2000");
  720.          break;
  721.  
  722.       case "97":
  723.          T.showGroup("group97");
  724.          break;
  725.  
  726.       default:
  727.          alert(wrapTextForAlert(MSG_Error, 80));
  728.          break;
  729.    }
  730.    T.refresh();
  731. }
  732.  
  733.  
  734. /////////////////////////////////////////////////////////////////////////////
  735. // Function
  736. //    getVersion
  737. //
  738. // Purpose
  739. //    Quickie function to get the version from the selected version
  740. //
  741. function getVersion()
  742. {
  743.    with(findObject("selectWordVersion"))
  744.    {
  745.       return options[selectedIndex].value;
  746.    }
  747. }
  748.  
  749.  
  750.  
  751. // ----- Check functions ----------------------------------------------------
  752.  
  753. /////////////////////////////////////////////////////////////////////////////
  754. function doRemoveMetaLink()
  755. {
  756.    switch(getVersion())
  757.    {
  758.       case "2000":
  759.          return CB.isChecked("removeMetaLink2000_detail");
  760.          break;
  761.          
  762.       case "97":
  763.          return CB.isChecked("removeMetaLink97_detail");
  764.          break;
  765.    }
  766.  
  767.    return false;
  768. }
  769.  
  770.  
  771. /////////////////////////////////////////////////////////////////////////////
  772. function doConvertSize(size)
  773. {
  774.    switch(size)
  775.    {
  776.       case "7":
  777.          return CB.isChecked("convertSize7_detail");
  778.       case "6":
  779.          return CB.isChecked("convertSize6_detail");
  780.       case "5":
  781.          return CB.isChecked("convertSize5_detail");
  782.       case "4":
  783.          return CB.isChecked("convertSize4_detail");
  784.       case "3":
  785.          return CB.isChecked("convertSize3_detail");
  786.       case "2":
  787.          return CB.isChecked("convertSize2_detail");
  788.       case "1":
  789.          return CB.isChecked("convertSize1_detail");
  790.    }
  791.  
  792.    return false;
  793. }
  794.  
  795.  
  796. /////////////////////////////////////////////////////////////////////////////
  797. // Function
  798. //    getDesiredFontSize
  799. //
  800. // Purpose
  801. //    Given a size, find out what the user has specified to change that
  802. //    size to.  This queries the dropdown box associated with the given
  803. //    size.
  804. //
  805. function getDesiredFontSize(size)
  806. {
  807.    var option;
  808.    
  809.    if(size.length != 1)
  810.       return "-1";
  811.  
  812.    if(size[0] < '1' || size[0] > '7')
  813.       return "-1";
  814.  
  815.    option = findObject("menuSize"+size);
  816.  
  817.    if(option != null)
  818.       return option.options[option.selectedIndex].value;
  819.  
  820.    return "-1";
  821. }
  822.  
  823.  
  824. /////////////////////////////////////////////////////////////////////////////
  825. function doRemoveXMLFromHTML()
  826. {
  827.    return CB.isChecked("removeXMLHTML2000_detail");
  828. }
  829.  
  830. /////////////////////////////////////////////////////////////////////////////
  831. function doRemoveXMLMarkup()
  832. {
  833.    return CB.isChecked("removeXMLmarkup2000_detail");
  834. }
  835.  
  836. /////////////////////////////////////////////////////////////////////////////
  837. function doRemoveIfs()
  838. {
  839.    return CB.isChecked("removeIf2000_detail");
  840. }
  841.  
  842. /////////////////////////////////////////////////////////////////////////////
  843. function doRemoveEmptyParas()
  844. {
  845.    return CB.isChecked("removeEmptyPara2000_detail");
  846. }
  847.  
  848. /////////////////////////////////////////////////////////////////////////////
  849. function doRemoveInlineCSS()
  850. {
  851.    return CB.isChecked("removeInlineCSS2000_detail");
  852. }
  853.  
  854. /////////////////////////////////////////////////////////////////////////////
  855. function doRemoveMSOStyleAttr()
  856. {
  857.    return CB.isChecked("removeInlineCSS2000_detail");
  858. }
  859.  
  860. /////////////////////////////////////////////////////////////////////////////
  861. function doRemoveNonCSSDeclaration()
  862. {
  863.    return CB.isChecked("removeNonCSS2000_detail");
  864. }
  865.  
  866. /////////////////////////////////////////////////////////////////////////////
  867. function doRemoveCSSFromTables()
  868. {
  869.    return CB.isChecked("removeCSSTable2000_detail");
  870. }
  871.  
  872. /////////////////////////////////////////////////////////////////////////////
  873. function doRemoveUnusedStyles()
  874. {
  875.    return CB.isChecked("removeUnusedCSS2000_detail");
  876. }
  877.  
  878. /////////////////////////////////////////////////////////////////////////////
  879. function doFixInvalidNesting()
  880. {
  881.    return CB.isChecked("removeInlineCSS2000_detail");
  882. }
  883.  
  884. /////////////////////////////////////////////////////////////////////////////
  885. function doSetBgColor()
  886. {
  887.    return CB.isChecked("setBgColor_basic");
  888. }
  889.  
  890. /////////////////////////////////////////////////////////////////////////////
  891. function doApplySourceFormatting()
  892. {
  893.    return CB.isChecked("applyFormatting_basic");
  894. }
  895.  
  896. /////////////////////////////////////////////////////////////////////////////
  897. function doShowLog()
  898. {
  899.    return CB.isChecked("showLog_basic");
  900. }
  901.  
  902. /////////////////////////////////////////////////////////////////////////////
  903. function doSaveSettings()
  904. {
  905.    return true;
  906. }
  907.  
  908.  
  909. /////////////////////////////////////////////////////////////////////////////
  910. // Function
  911. //    ProcessWord2000
  912. //
  913. // Purpose
  914. //    This is the main function for doing Word 2000 processing on the
  915. //    document.
  916. //
  917. function ProcessWord2000()
  918. {
  919.    if(doRemoveXMLFromHTML())
  920.       removeXMLFromHTML();
  921.  
  922.    if(doRemoveXMLMarkup())
  923.       removeXMLMarkup();
  924.  
  925.    if(doRemoveIfs())
  926.      removeIfs();
  927.  
  928.    if(doRemoveMSOStyleAttr())
  929.       removeMSOStyleAttr();
  930.  
  931.    if(doRemoveEmptyParas())
  932.       removeEmptyParas();
  933.  
  934.    if(doRemoveCSSFromTables())
  935.       removeCSSFromTables();
  936.  
  937.    if(doRemoveNonCSSDeclaration())
  938.       removeNonCSSDeclaration();
  939.  
  940.    if(doRemoveInlineCSS())
  941.       removeInlineCSS();
  942.  
  943.    if(doRemoveUnusedStyles())
  944.       removeUnusedStyles();
  945.  
  946.    // We are done.  Do some general cleanup
  947.    formatCSS();
  948. }
  949.  
  950.  
  951. /////////////////////////////////////////////////////////////////////////////
  952. function RemoveEmptyTags()
  953. {
  954.    var body = findTag("body");
  955.    var emptyTags = new Array();
  956.    var tag;
  957.  
  958.    // First find all of the tags that are empty inside the body.
  959.    traverse(body, findEmptyTags, null, null, emptyTags);
  960.  
  961.    // Now remove them.
  962.    while((tag = emptyTags.pop()) != null)
  963.    {
  964.       if (dw.nodeExists(tag))
  965.          tag.outerHTML = tag.innerHTML;
  966.    }
  967. }
  968.  
  969. /////////////////////////////////////////////////////////////////////////////
  970. function findEmptyTags(tag, emptyTags)
  971. {
  972.    var tagName = tag.tagName;
  973.    var html;
  974.    var regx;
  975.    var result;
  976.  
  977.    switch(tagName.toUpperCase())
  978.    {
  979.       // Add new empty tags to be removed here.
  980.       case "DIV":
  981.       case "SPAN":
  982.       case "FONT":
  983.       
  984.          // Do a match to see if the tag is empty (no attributes)
  985.          // If it is add it to the list of empty tags that we
  986.          // will remove from the doc.
  987.          html = tag.outerHTML;
  988.          regx = new RegExp("<"+tagName+">", "i");
  989.          result = regx.exec(html);
  990.          
  991.          if(result != null && result.index != -1)
  992.             emptyTags.push(tag);
  993.  
  994.          break;
  995.    }
  996.  
  997.    return true;
  998. }
  999.  
  1000.  
  1001. /////////////////////////////////////////////////////////////////////////////
  1002. // Function
  1003. //    ProcessWord97
  1004. //
  1005. // Purpose
  1006. //    This is the main function for doing Word 97 processing on the
  1007. //    document.
  1008. //
  1009. function ProcessWord97()
  1010. {
  1011.    if(doRemoveMetaLink())
  1012.       removeMetaLink();
  1013.  
  1014.    convertFontSizes(); 
  1015.  
  1016.    if(doFixInvalidNesting())
  1017.       fixInvalidNesting();
  1018. }
  1019.  
  1020.  
  1021. function convertFontSizes()
  1022. {
  1023.    traverse(null, convertFontSizeHandler);
  1024.  
  1025.    // post processing will strip the empty <font> tags.
  1026. }
  1027.  
  1028.  
  1029. //////////////////////////////////////////////////////////////////////////////
  1030. // Function
  1031. //    convertFontSizeHandler
  1032. //
  1033. // Purpose
  1034. //    Callback that searches for font tags to convert.
  1035. //
  1036. function convertFontSizeHandler(tag)
  1037. {
  1038.    if(tag.tagName.toUpperCase() == "FONT")
  1039.    {
  1040.       var size = tag.getAttribute("size");
  1041.       var desiredSize;
  1042.  
  1043.       if(size != null && doConvertSize(size))
  1044.       {
  1045.          desiredSize = getDesiredFontSize(size);
  1046.          switch(desiredSize)
  1047.          {
  1048.             case "-1":  // don't change anything
  1049.                break;
  1050.  
  1051.             case "0":  // use default size
  1052.                tag.removeAttribute("size");
  1053.                gFontsConverted++;
  1054.                break;
  1055.                
  1056.             case "1":
  1057.             case "2":
  1058.             case "3":
  1059.             case "4":
  1060.             case "5":
  1061.             case "6":
  1062.             case "7":
  1063.                tag.setAttribute("size", desiredSize);
  1064.                gFontsConverted++;
  1065.                break;
  1066.  
  1067.             case "h1":
  1068.             case "h2":
  1069.             case "h3":
  1070.             case "h4":
  1071.             case "h5":
  1072.             case "h6":
  1073.                // If this font tag is not contained within another block tag,
  1074.                // we can convert it to a header.  If the font is contained
  1075.                // within a block tag, it is an inline font size change.  We
  1076.                // don't want to convert those to headers since headers create
  1077.                // vertical white space.
  1078.                if(!isInsideTag(tag, "p,h1,h2,h3,h4,h5,h6"))
  1079.                {
  1080.                   // We remove the size attribute from the <font> tag
  1081.                   // and wrap the font tag and all its content with
  1082.                   // the appropriate heading.
  1083.                   tag.removeAttribute("size");
  1084.                   
  1085.                   html = tag.outerHTML;
  1086.  
  1087.                   // Strip any internal <p>'s that we might have.  We don't
  1088.                   // need them since we are converting this to a header.
  1089.                   html = html.replace(/<\/?P[^>]*>/ig, "");
  1090.                   
  1091.                   html = "<"+desiredSize+">" + html + "</"+desiredSize+">";
  1092.                   tag.outerHTML = html;
  1093.  
  1094.                   gFontsConverted++;
  1095.  
  1096.                   // Note, we could be leaving behind an empty <font> tag.
  1097.                   // But, this is OK.  The general post processing will
  1098.                   // clean these up.
  1099.                }
  1100.                break;
  1101.          }
  1102.       }
  1103.    }
  1104.  
  1105.    // Keep traversing...
  1106.    return true;
  1107. }
  1108.  
  1109.  
  1110. /////////////////////////////////////////////////////////////////////////////
  1111. // Function
  1112. //    fixInvalidNesting
  1113. //
  1114. // Purpose
  1115. //    Word 97 has no clue about HTML structure.  Most HTML documents that
  1116. //    it generates have overlapped tags, and invalid nesting structures.
  1117. //    This function aims to clean up that mess.
  1118. //
  1119. //    Note!  This is a very specialized case for Word 97.  This will
  1120. //    not fix all general cases of invalid nesting.
  1121. //
  1122. function fixInvalidNesting()
  1123. {
  1124.    traverse(null, fixHandler);
  1125.    traverse(null, removeMarkedTags);
  1126. }
  1127.  
  1128.  
  1129. /////////////////////////////////////////////////////////////////////////////
  1130. // Function
  1131. //    fixHandler
  1132. //
  1133. // Purpose
  1134. //    Callback for fixing up invalidly nested tags.  This is very specific
  1135. //    to how Word 97 generates its HTML.  This will NOT fix any general
  1136. //    case of invalid HTML (that problem is actually quite difficult).
  1137. //
  1138. function fixHandler(tag, nestingFixes)
  1139. {
  1140.    var html;
  1141.    var tagName = tag.tagName.toUpperCase();
  1142.    
  1143.    // If this is a <p> or a header, we need to do some work.
  1144.    if(tagName == "P" || tagName == "LI" || (tagName.match(/h[1-6]/i) != null))
  1145.    {
  1146.       // Fix up them tags
  1147.  
  1148.       var pCase = tag.tagName;  // maintain upper/lower case
  1149.       var parent = tag.parentNode;
  1150.       var innerMostHTML = tag.innerHTML;
  1151.  
  1152.       while(parent != null)
  1153.       {
  1154.          if(parent.tagName)
  1155.          {
  1156.             switch(parent.tagName.toUpperCase())
  1157.             {
  1158.                case "FONT":
  1159.                case "B":
  1160.                case "I":
  1161.                   parent.removeAttribute("TO_BE_DELETED");
  1162.                   html = parent.outerHTML;
  1163.                   parent.setAttribute("TO_BE_DELETED",true);
  1164.  
  1165.                   // We use match here to make sure we maintain any tag attributes.
  1166.                   startTag = html.match(/<[^>]*>/);
  1167.  
  1168.                   if(startTag != null)
  1169.                   {
  1170.                      innerMostHTML = startTag[0] + innerMostHTML +
  1171.                         "</" + parent.tagName + ">";
  1172.                   }
  1173.                   break;
  1174.             }
  1175.  
  1176.          }
  1177.          
  1178.          parent = parent.parentNode;
  1179.       }
  1180.       tag.innerHTML = innerMostHTML;  //actually change the internal tag
  1181.    }
  1182.  
  1183.    return true;
  1184. }
  1185.  
  1186.  
  1187. function removeMarkedTags(tag) {
  1188.   if (tag.getAttribute("TO_BE_DELETED")) {
  1189.     tag.outerHTML = tag.innerHTML;         //blow away outer tag
  1190.   }
  1191.   return true;
  1192. }
  1193.  
  1194.  
  1195. /////////////////////////////////////////////////////////////////////////////
  1196. // Function
  1197. //    removeXMLFromHTML
  1198. //
  1199. // Purpose
  1200. //    Word puts some useless XML markup in the start <html> tag, nuke it.
  1201. //
  1202. function removeXMLFromHTML()
  1203. {
  1204.    var root = getRootNode();
  1205.    var html = root.outerHTML;
  1206.  
  1207.    // We have 2 submatches, "<html", everything after "<html" to the ending
  1208.    // ">".  We want to throw out everything between "<html" and the end.
  1209.    // So, we will just keep $1.
  1210.    html = html.replace(/(<html)([^>]*)/, "$1");
  1211.  
  1212.    root.outerHTML = html;
  1213. }
  1214.  
  1215.  
  1216. /////////////////////////////////////////////////////////////////////////////
  1217. // Function
  1218. //    removeXMLMarkup
  1219. //
  1220. // Purpose
  1221. //    Word puts some random, useless XML markup in the body.  Strip it.
  1222. //
  1223. function removeXMLMarkup()
  1224. {
  1225.    var root = dw.getDocumentDOM('document').documentElement;
  1226.    var html = root.outerHTML;
  1227.  
  1228.    if(doShowLog())
  1229.    {
  1230.       var match;
  1231.  
  1232.       match = html.match(/<o:p>/g);
  1233.       gRemoveWordXML += (match != null ? match.length : 0);
  1234.       
  1235.       match = html.match(/<\/o:p>/g);
  1236.       gRemoveWordXML += (match != null ? match.length : 0);
  1237.    }
  1238.    
  1239.    // Remove all instances of <o:p></o:p>
  1240.    html = html.replace(/<o:p>/g, "");
  1241.    html = html.replace(/<\/o:p>/g, "");
  1242.  
  1243.    // If we find any other instances of XML markup, we can add it here.
  1244.    
  1245.    root.outerHTML = html;
  1246. }
  1247.  
  1248.  
  1249. /////////////////////////////////////////////////////////////////////////////
  1250. // Function
  1251. //    removeIfs
  1252. //
  1253. // Purpose
  1254. //    Word uses many <![if...]> style comments for its own internal
  1255. //    purposes, which are useless in HTML.  This function strips those.
  1256. //
  1257. function removeIfs()
  1258. {
  1259.    traverse(null, null, null, ifHandler);
  1260.  
  1261.    var root = dw.getDocumentDOM('document').documentElement;
  1262.    var html = root.outerHTML;
  1263.  
  1264.    // clean up those empty comments!
  1265.    html = html.replace(/<!-*>/g, "");
  1266.    root.outerHTML = html;
  1267. }
  1268.  
  1269.  
  1270. /////////////////////////////////////////////////////////////////////////////
  1271. // Function
  1272. //    ifHandler
  1273. //
  1274. // Purpose
  1275. //    Find those pesky "if" conditionals that Word 2000 puts in the HTML
  1276. //    and nuke'em.
  1277. //
  1278. function ifHandler(comment)
  1279. {
  1280.    var html = comment.data;
  1281.    var matchif = html.match(/\[if /);
  1282.    var matchendif = html.match(/\[endif/);
  1283.    
  1284.    if(matchif != null || matchendif != null)
  1285.    {
  1286.       gRemoveConditionals++;
  1287.       comment.data = "";
  1288.    }
  1289.  
  1290.    return true;
  1291. }
  1292.  
  1293.  
  1294. /////////////////////////////////////////////////////////////////////////////
  1295. // Function
  1296. //    removeMSOStyleAttr
  1297. //
  1298. // Purpose
  1299. //    Microsoft Word uses many custom CSS attributes.  This function hunts
  1300. //    them down and removes them.
  1301. //
  1302. function removeMSOStyleAttr()
  1303. {
  1304.    var root = dw.getDocumentDOM('document').documentElement;
  1305.    var html = root.outerHTML;
  1306.    
  1307.    RegExp.multiline = true;
  1308.  
  1309.    if(doShowLog())
  1310.    {
  1311.       // NOTE!  This is highly ineffiecient since we are doing the regexp
  1312.       // searchs twice (once to count, once to do the actual replaces).
  1313.       // If there is a better way to know how many times a replace()
  1314.       // does its thing, we should do that.
  1315.       var match;
  1316.  
  1317.       match = html.match(/mso-[^:]*:"[^"]*";/g, "");
  1318.       if (match) gRemovemsoStyle += match.length;
  1319.       match = html.match(/mso-[^;'"]*;*(\n|\r)*/g, "");
  1320.       if (match) gRemovemsoStyle += match.length;
  1321.       match = html.match(/page-break-after[^;]*;/g, "");
  1322.       if (match) gRemovemsoStyle += match.length;
  1323.       match = html.match(/ style=['"]tab-interval:[^'"]*['"]/g, "");
  1324.       if (match) gRemovemsoStyle += match.length;
  1325.    }
  1326.  
  1327.    // This finds the mso-*:"SomeStuff"; style attributes and sets them to be nothing.
  1328.    html = html.replace(/mso-[^:]*:"[^"]*";/g, "");
  1329.  
  1330.    // This finds the other mso-* style attibutes.
  1331.    html = html.replace(/mso-[^;'"]*;*(\n|\r)*/g, "");
  1332.  
  1333.    // Remove some other Word-only css style attributes.
  1334.    html = html.replace(/page-break-after[^;]*;/g, "");
  1335.    html = html.replace(/ style=['"]tab-interval:[^'"]*['"]/g, "");
  1336.    
  1337.    root.outerHTML = html;
  1338. }
  1339.  
  1340.  
  1341. /////////////////////////////////////////////////////////////////////////////
  1342. // Function
  1343. //    removeEmptyParas
  1344. //
  1345. // Purpose
  1346. //    Word sets paragraph bottom margins to zero, then inserts empty
  1347. //    (containing  ) paragraphs to maintain the vertical spacing
  1348. //    expected.  This is soley for its own purpose and is redundant
  1349. //    for HTML.  This function removes margin definitions and removes
  1350. //    those pesky empty paragraphs.
  1351. //
  1352. function removeEmptyParas()
  1353. {
  1354.    var root = dw.getDocumentDOM('document').documentElement;
  1355.    var style = findTag("style");
  1356.    var html = null;
  1357.    
  1358.    if(style != null)
  1359.    {
  1360.       // Clean out the nonsense zero margin definitions from the
  1361.       // style block.
  1362.       html = style.innerHTML;
  1363.  
  1364.       // Just strip all of those wacky margins that Word puts in there.
  1365.       html = html.replace(/margin[^:]*:[^\n\r]*/g, "");
  1366.  
  1367.       style.innerHTML = html;
  1368.    }
  1369.  
  1370.    // Next, go through the document and strip out those inline margins too.
  1371.    traverse(root, stripMargins);
  1372.  
  1373.    // Now go find those empty paragraphs and remove them.
  1374.    traverse(root, paraHandler);
  1375. }
  1376.  
  1377.  
  1378. /////////////////////////////////////////////////////////////////////////////
  1379. // Function
  1380. //    stripMargins
  1381. //
  1382. // Purpose
  1383. //    Word uses a lot of CSS margin settings in attempt to make the HTML
  1384. //    version look exactly like the native Word version.  In general, this
  1385. //    is un wanted, so lets remove all this stuff.
  1386. //
  1387. function stripMargins(tag)
  1388. {
  1389.    var style = tag.getAttribute("style");
  1390.  
  1391.    if(style != null)
  1392.    {
  1393.       if(doShowLog())
  1394.       {
  1395.          // Note, if there is a better way to count (if replace can be forced
  1396.          // to report how many replaces it did), we should do that.  Because
  1397.          // this takes extra processing effort to count this stuff using
  1398.          // "match".
  1399.          
  1400.          var match;
  1401.  
  1402.          match = style.match(/margin[^"';]*;?/g);
  1403.          gRemoveMargins += (match != null ? match.length : 0);
  1404.          match = style.match(/text-indent[^"';]*;?/g);
  1405.          gRemoveMargins += (match != null ? match.length : 0);
  1406.          match = style.match(/tab-stops:[^'";]*;?/g);
  1407.          gRemoveMargins += (match != null ? match.length : 0);
  1408.       }
  1409.  
  1410.       style = style.replace(/margin[^"';]*;?/g, "");
  1411.       style = style.replace(/text-indent[^"';]*;?/g, "");
  1412.       style = style.replace(/tab-stops:[^'";]*;?/g, "");
  1413.       
  1414.       if(style == null || style == "")
  1415.          tag.removeAttribute("style");
  1416.       else
  1417.          tag.setAttribute("style", style);
  1418.    }
  1419.    
  1420.    return true;
  1421. }
  1422.  
  1423.  
  1424. /////////////////////////////////////////////////////////////////////////////
  1425. // Function
  1426. //    paraHandler
  1427. //
  1428. // Purpose
  1429. //    Callback that looks for empty <p>'s and deletes them.  After
  1430. //    doing some processing removing stuff, we can easily end up
  1431. //    with empty paragraphs.  This just cleans up after ourselves.
  1432. //
  1433. function paraHandler(tag)
  1434. {
  1435.    tagName = tag.tagName;
  1436.    if(tagName.toUpperCase() == "P")
  1437.    {
  1438.       text = tag.innerHTML;
  1439.  
  1440.       // Make sure there are not any content generating HTML tags, this
  1441.       // prevents us from removing say, <img> in the next step.
  1442.       if(containsContentTags(text))
  1443.          return true; // Keep searching in the traverse
  1444.          
  1445.       // Ok, we don't have any content tags.  We are save to strip any
  1446.       // other tags (font, b, etc).
  1447.       text = text.replace(/<[^>]*>/g, "");
  1448.  
  1449.       // Strip whitespace
  1450.       text = text.replace(/\s/g, "");
  1451.  
  1452.       // Strip  s
  1453.       text = text.replace(/ /g, "");
  1454.  
  1455.       // After doing all that, if there is nothing left, this paragraph is empty.
  1456.       if(text == "" || text == null)
  1457.       {
  1458.          gRemoveEmptyParas++;
  1459.          tag.outerHTML = "";
  1460.       }
  1461.    }
  1462.  
  1463.    return true;
  1464. }
  1465.  
  1466.  
  1467. /////////////////////////////////////////////////////////////////////////////
  1468. // Function
  1469. //    containsContentTags
  1470. //
  1471. // Purpose
  1472. //    Given a string that contains some HTML, check to see if we have
  1473. //    any tags that generate visible content.
  1474. //
  1475. // Returns
  1476. //    zero (false) if no content generating tags are found.  Non-zero
  1477. //    value if anything is found.
  1478. //
  1479. function containsContentTags(text)
  1480. {
  1481.    var index = 0;
  1482.  
  1483.    // text.search returns -1 if it does not find anything.  So by adding
  1484.    // 1 and bitwise or-ing the result, we maintain zero if no match.
  1485.    index |= text.search(/<hr/i) + 1;
  1486.    index |= text.search(/<img/i) + 1;
  1487.    index |= text.search(/<input/i) + 1;
  1488.    index |= text.search(/<object/i) + 1;
  1489.    index |= text.search(/<table/i) + 1;
  1490.    index |= text.search(/<textarea/i) + 1;
  1491.    index |= text.search(/<embed/i) + 1;
  1492.  
  1493.    // if index is still zero after all that, we don't have any content tags.
  1494.    
  1495.    return index;
  1496. }
  1497.  
  1498.  
  1499. /////////////////////////////////////////////////////////////////////////////
  1500. // Function
  1501. //    formatCSS
  1502. //
  1503. // Purpose
  1504. //    When we modify or remove stuff from the <style> block we leave it in
  1505. //    a not so pretty state.  This will clean it up so it looks nice.
  1506. //
  1507. function formatCSS()
  1508. {
  1509.    var style = findTag("style");
  1510.  
  1511.    if(style != null)
  1512.    {
  1513.       var html = style.innerHTML;
  1514.       
  1515.       // We need multiline turned on for this.
  1516.       var multiline = RegExp.multiline;
  1517.       RegExp.multiline = true;
  1518.  
  1519.       // Lets just get rid of those comments that Word puts in there
  1520.       html = html.replace(/\/\*.*\*\//g, "");
  1521.  
  1522.       // Clean up the whitespace between the start and end brackets.
  1523.       html = html.replace(/\s*\}/g, "}");
  1524.       html = html.replace(/\{\s*/g, "{");
  1525.  
  1526.       // Make sure anything that is indented is indented only one tab.
  1527.       html = html.replace(/^\t+/g, "\t");
  1528.  
  1529.       // Make sure the style names are on their own line.
  1530.       html = html.replace(/\}/g, "}\n");
  1531.  
  1532.       // This will delete blank lines in the style declaration
  1533.       html = html.replace(/^[ \t]*(\r|\n)+/g, "");
  1534.  
  1535.       // Set it back
  1536.       RegExp.multiline = multiline;
  1537.  
  1538.       style.innerHTML = html;
  1539.    }
  1540. }
  1541.  
  1542.  
  1543.  
  1544. /////////////////////////////////////////////////////////////////////////////
  1545. // Function
  1546. //    removeCSSFromTables
  1547. //
  1548. // Purpose
  1549. //    Word tends to go overboard with CSS with tables.  Almost all of it
  1550. //    is used to maintain the "Word appearance" and is generally undesirable
  1551. //    for use with HTML.  So, this function just strips it all.
  1552. //
  1553. function removeCSSFromTables()
  1554. {
  1555.    // Find each table tag and do some processing on it.
  1556.    traverse(null, convertCSSInTables);
  1557. }
  1558.  
  1559.  
  1560. /////////////////////////////////////////////////////////////////////////////
  1561. // Function
  1562. //    convertCSSInTables
  1563. //
  1564. // Purpose
  1565. //    We want to strip the CSS applied to tables and their cells.
  1566. //    However, some of these styles can be converted into HTML
  1567. //    attributes.  This function converts any styles we can to
  1568. //    HTML attributes and then removes the style tag.
  1569. //
  1570. function convertCSSInTables(tag)
  1571. {
  1572.    var tagName = tag.tagName.toUpperCase();
  1573.    var style;
  1574.    var match;
  1575.  
  1576.    if(tagName == "TABLE")
  1577.    {
  1578.       style = tag.getAttribute("style");
  1579.  
  1580.       if(style != null && style != "")
  1581.       {
  1582.          match = style.match(/border-color: *([^;'"]*)/);
  1583.  
  1584.          if(match != null)
  1585.             tag.setAttribute("bordercolor", match[1]);
  1586.  
  1587.          tag.removeAttribute("style");
  1588.          
  1589.          gRemoveTableCSS++;
  1590.       }
  1591.    }
  1592.    else if(tagName == "TR")
  1593.    {
  1594.       // TRs do not have any styles that we want to keep.
  1595.       tag.removeAttribute("style");
  1596.  
  1597.       gRemoveTableCSS++;
  1598.    }
  1599.    else if(tagName == "TD")
  1600.    {
  1601.       style = tag.getAttribute("style");
  1602.  
  1603.       if(style != null && style != "")
  1604.       {
  1605.          match = style.match(/background: *([^;'"]*)/);
  1606.          
  1607.          if(match != null)
  1608.             tag.setAttribute("bgcolor", match[1]);
  1609.          
  1610.          // Lastly, kill the style tag.
  1611.          tag.removeAttribute("style");
  1612.  
  1613.          gRemoveTableCSS++;
  1614.       }
  1615.    }
  1616.  
  1617.    return true;
  1618. }
  1619.  
  1620.  
  1621.  
  1622. /////////////////////////////////////////////////////////////////////////////
  1623. // Function
  1624. //    removeNonCSSDeclaration
  1625. //
  1626. // Purpose
  1627. //    Word puts a number of non-standard CSS style declarations in the
  1628. //    style block.  This will strip them, and remove any references to
  1629. //    them.
  1630. //
  1631. function removeNonCSSDeclaration()
  1632. {
  1633.    var root = dw.getDocumentDOM('document').documentElement;
  1634.    var data = new Array();
  1635.    var invalidList;
  1636.    var style;
  1637.  
  1638.    style = findTag("style");
  1639.    if(style != null)
  1640.    {
  1641.       var html = style.innerHTML;
  1642.       var htmlLeft, htmlRight;
  1643.  
  1644.       // First, we need to get a list of all the invalid style names.  This
  1645.       // way, we can go through the file and remove the references to them.
  1646.       invalidList = html.match(/^@[^\s]* .*/g);
  1647.  
  1648.       if(invalidList != null)
  1649.       {
  1650.          // Log the number of invalid CSS styles we find.
  1651.          gRemoveNonCSS += invalidList.length;
  1652.          
  1653.          for(i = 0; i < invalidList.length; i++)
  1654.          {
  1655.             invalidList[i] = invalidList[i].replace(/@\w* /g, "");
  1656.             invalidList[i] = invalidList[i].replace(/(\r|\n)*/g, "");
  1657.          }
  1658.       }
  1659.  
  1660.       // This removes the invalid "@" CSS declarations
  1661.       html = html.replace(/^@[^}]*}/g, "");
  1662.       
  1663.       // Now we need to go and clean out everything that referenced the
  1664.       // invalid styles.  First lets finish cleaning the style block.      
  1665.       if(invalidList != null)
  1666.       {
  1667.          var regx = new RegExp();
  1668.          var htmlLeft, htmlRight;
  1669.          var result;
  1670.          
  1671.          for(i = 0; i < invalidList.length; i++)
  1672.          {
  1673.             // Find stuff of the form "div.Section1 ... { ... }"
  1674.             regx.compile("^.*\\."+invalidList[i]+"[^}]*}", "g");
  1675.  
  1676.             while((result = regx.exec(html)) != null)
  1677.             {
  1678.                htmlLeft = html.substring(0, result.index);
  1679.                htmlRight = html.substring(result.index + result[0].length);
  1680.  
  1681.                // Remove the match
  1682.                html = htmlLeft + htmlRight;
  1683.             }
  1684.          }
  1685.             
  1686.          style.innerHTML = html;
  1687.       }
  1688.       else
  1689.       {
  1690.          style.innerHTML = html;
  1691.       }
  1692.    }
  1693.  
  1694.    // OK, we cleaned up the style block, now we just need to go
  1695.    // through the rest of the document and remove any references
  1696.    // to the invalid CSS classes.
  1697.    if(invalidList != null)
  1698.    {
  1699.       root = dw.getDocumentDOM('document').documentElement;
  1700.       var html = root.outerHTML;
  1701.       var regx = new RegExp();
  1702.  
  1703.       for(i = 0; i < invalidList.length; i++)
  1704.       {
  1705.          regx.compile(" class=(\")?"+invalidList[i]+"\\1", "g");
  1706.          
  1707.          while((result = regx.exec(html)) != null)
  1708.          {
  1709.             htmlLeft = html.substring(0, result.index);
  1710.             htmlRight = html.substring(result.index + result[0].length);
  1711.  
  1712.             html = htmlLeft + htmlRight;
  1713.          }
  1714.       }
  1715.  
  1716.       root.outerHTML = html;
  1717.    }
  1718. }
  1719.  
  1720.  
  1721.  
  1722. /////////////////////////////////////////////////////////////////////////////
  1723. // Function
  1724. //    removeMetaLink
  1725. //
  1726. // Purpose
  1727. //    Removes those nasty Microsoft-only Meta tags.
  1728. //
  1729. function removeMetaLink()
  1730. {
  1731.    var head = findTag("head");
  1732.  
  1733.    traverse(head, removeMetasHandler);
  1734. }
  1735.  
  1736.  
  1737. /////////////////////////////////////////////////////////////////////////////
  1738. // Function
  1739. //    removeMetasHandler
  1740. //
  1741. // Purpose
  1742. //    This function finds the meta tags in the document and checks
  1743. //    to see if they have any MS junk in them.  If they do, bye bye.
  1744. //
  1745. function removeMetasHandler(tag, metaTags)
  1746. {
  1747.    var tagName = tag.tagName.toUpperCase();
  1748.    var html;
  1749.    
  1750.    if(tagName == "META")
  1751.    {
  1752.       html = tag.outerHTML;
  1753.  
  1754.       index = html.search(/(word|microsoft)/i);
  1755.  
  1756.       if(index != -1)
  1757.       {
  1758.          // This tag contains some Word junk, nuke it.
  1759.          tag.outerHTML="";
  1760.  
  1761.          gRemoveMetaTags++;
  1762.       }
  1763.    }
  1764.    else if(tagName == "LINK")
  1765.    {
  1766.       var rel = tag.getAttribute("rel");
  1767.  
  1768.       if(rel == "File-List")
  1769.       {
  1770.          tag.outerHTML = "";
  1771.  
  1772.          gRemoveMetaTags++;
  1773.       }
  1774.    }
  1775.  
  1776.    return true;
  1777. }
  1778.  
  1779.  
  1780. /////////////////////////////////////////////////////////////////////////////
  1781. function setBgColor()
  1782. {
  1783.    var body = findTag("body");
  1784.  
  1785.    if(body != null)
  1786.    {
  1787.       var colorObj = findObject("bgcolor_basic");
  1788.       var color = (colorObj == null ? null : colorObj.value);
  1789.  
  1790.       if(color != null)
  1791.       {
  1792.          body.setAttribute("bgcolor", color);
  1793.          
  1794.          gBackgroundSet = color;
  1795.       }
  1796.    }
  1797. }
  1798.  
  1799.  
  1800.  
  1801. /////////////////////////////////////////////////////////////////////////////
  1802. // Function
  1803. //    removeInlineCSS
  1804. //
  1805. // Purpose
  1806. //    Word 2000 loves to declare "normal" styles and then apply them to
  1807. //    every block in the document.  Let's just set it on the body and
  1808. //    remove it from everything else.
  1809. //
  1810. function removeInlineCSS()
  1811. {
  1812.  
  1813.    var style = findTag("style");
  1814.  
  1815.    if(style != null)
  1816.    {
  1817.       var index;
  1818.       
  1819.       html = style.innerHTML;
  1820.  
  1821.       index = html.search(/\.(MsoNormal)/i);
  1822.       if(index != -1)
  1823.       {
  1824.          // Lets strip out the "normal" styles and make only one.  Word
  1825.          // tends to have stuff like p.MsoNormal, li.MsoNormal, etc.
  1826.          html = html.replace(/^\s*\w*\.MsoNormal/ig, ".TempNormal");
  1827.  
  1828.          // Change the first one we find to "FirstNormal"
  1829.          html = html.replace(/\.TempNormal/, ".FirstNormal");
  1830.  
  1831.          // Remove the rest.
  1832.          html = html.replace(/\.TempNormal/g, "");
  1833.  
  1834.          // Change the first normal to just "Normal"
  1835.          html = html.replace(/^.*\.FirstNormal[^\r\n]*/, ".Normal");
  1836.  
  1837.          style.innerHTML = html;
  1838.  
  1839.          // Now we need to go and remove all references to the old class.
  1840.          var body = findTag("body");
  1841.  
  1842.          html = body.innerHTML;
  1843.  
  1844.          if(doShowLog())
  1845.          {
  1846.             var match = html.match(/ class=MsoNormal/g);
  1847.             gRemoveInlineCSS += (match != null ? match.length : 0);
  1848.          }
  1849.  
  1850.          html = html.replace(/ class=MsoNormal/g, "");
  1851.          body.innerHTML = html;
  1852.  
  1853.          body.setAttribute("class", "Normal");
  1854.   
  1855.          // Since body styles do not filter down into table cells,
  1856.          // we need to set the styles on the table cells too.
  1857.          traverse(null, setTDStyles);
  1858.       }
  1859.    }
  1860. }
  1861.  
  1862.  
  1863. /////////////////////////////////////////////////////////////////////////////
  1864. // Function
  1865. //    setTDStyles
  1866. //
  1867. // Purpose
  1868. //    We have removed the styles from individual paragraphs and the body
  1869. //    style does not filter down into the table cells, so we need to set
  1870. //    the style on the table cells too.
  1871. //
  1872. function setTDStyles(tag)
  1873. {
  1874.    if(tag.tagName.toUpperCase() == "TD")
  1875.    {
  1876.       tag.setAttribute("class", "Normal");
  1877.    }
  1878.  
  1879.    return true;
  1880. }
  1881.  
  1882.       
  1883. /////////////////////////////////////////////////////////////////////////////
  1884. // Function
  1885. //    removeUnusedStyles
  1886. //
  1887. // Purpose
  1888. //    After we have done all of our house cleaning, some styles defined
  1889. //    in the head may no longer be used anywhere.  If they are no longer
  1890. //    used, we will blow them away.
  1891. //
  1892. function removeUnusedStyles()
  1893. {
  1894.    var style = findTag("style");
  1895.    var html;
  1896.    var classes;
  1897.  
  1898.    if(style != null)
  1899.    {
  1900.       html = style.innerHTML;
  1901.  
  1902.       // Put each style class in an array.
  1903.       classes = html.match(/\.?\w*\s*\{[^}]*\}/g);
  1904.  
  1905.       if(classes != null)
  1906.       {
  1907.          var classNames = new Array(classes.length);
  1908.          var regx = new RegExp();
  1909.          
  1910.          // Clean up the matches so we only have the class name.
  1911.          for(i = 0; i < classes.length; i++)
  1912.             classNames[i] = classes[i].replace(/^\s*\.?(\w*)\s*\{[^}]*\}/g, "$1");
  1913.  
  1914.          body = findTag("body");
  1915.          bodyhtml = body.outerHTML;
  1916.          
  1917.          // Now search in the body to see if we use them anywhere.
  1918.          for(i = 0; i < classes.length; i++)
  1919.          {
  1920.             regx.compile("class=['\"]?" + classNames[i], "g");
  1921.  
  1922.             result = regx.exec(bodyhtml);
  1923.  
  1924.             if(result == null)
  1925.             {
  1926.                // this style is not used.  Nuke it.
  1927.                classes[i] = "";
  1928.  
  1929.                gRemoveUnusedCSS++;
  1930.             }
  1931.          }
  1932.  
  1933.          // Now reconstruct the style block
  1934.          html = "\n<!--\n";
  1935.  
  1936.          for(i = 0; i < classes.length; i++)
  1937.             html += classes[i];
  1938.  
  1939.          html += "\n-->\n";
  1940.  
  1941.          style.innerHTML = html;
  1942.       }
  1943.    }
  1944. }
  1945.  
  1946. //*************** Pg1 Class *****************
  1947.  
  1948. //This is an example of a page class to be used with the TabControl.
  1949. //Uncomment the alert() calls to display the various events as they occur.
  1950.  
  1951. function Pg1(theTabLabel) {
  1952.   this.tabLabel = theTabLabel;
  1953. }
  1954. Pg1.prototype.getTabLabel = Pg1_getTabLabel;
  1955.  
  1956.  
  1957. function Pg1_getTabLabel() {
  1958.   return this.tabLabel;
  1959. }
  1960.  
  1961. //***************** End of Pg1 Class ******************
  1962. //*************** Pg2 Class *****************
  1963.  
  1964. //This is an example of a page class to be used with the TabControl.
  1965. //Uncomment the alert() calls to display the various events as they occur.
  1966.  
  1967. function Pg2(theTabLabel) {
  1968.   this.tabLabel = theTabLabel;
  1969. }
  1970. Pg2.prototype.getTabLabel = Pg2_getTabLabel;
  1971.  
  1972.  
  1973. function Pg2_getTabLabel() {
  1974.   return this.tabLabel;
  1975. }
  1976.  
  1977. //***************** End of Pg2 Class ******************
  1978. //*************** Pg3 Class *****************
  1979.  
  1980. //This is an example of a page class to be used with the TabControl.
  1981. //Uncomment the alert() calls to display the various events as they occur.
  1982.  
  1983. function Pg3(theTabLabel) {
  1984.   this.tabLabel = theTabLabel;
  1985.   this.loaded = false;
  1986. }
  1987. Pg3.prototype.getTabLabel = Pg3_getTabLabel;
  1988. Pg3.prototype.canLoad = Pg3_canLoad;
  1989. Pg3.prototype.unload = Pg3_unload;
  1990. Pg3.prototype.lastUnload = Pg3_lastUnload;
  1991.  
  1992.  
  1993. function Pg3_getTabLabel() {
  1994.   return this.tabLabel;
  1995. }
  1996.  
  1997. function Pg3_canLoad() {
  1998.   if (!this.loaded) {
  1999.     initDropDowns();
  2000.     setDropDownStates();
  2001.     this.loaded = true;
  2002.   }
  2003.   return true;
  2004. }
  2005.  
  2006. function Pg3_unload() {
  2007.   T.obj.visibility = "hidden";
  2008.   T.obj.visibility = "visible";
  2009.   return true;
  2010. }
  2011.  
  2012. function Pg3_lastUnload() {
  2013.   return this.canLoad();     //ensure dropdowns are initted before we do our work
  2014. }
  2015. //***************** End of Pg3 Class ******************
  2016.